<?

import("japha.io.PrintStream");
import("japha.text.NumberFormat");
import("japha.util.Enumeration");

require_once "../framework/AssertionFailedError.php";
require_once "../framework/Test.php";
require_once "../framework/TestFailure.php";
require_once "../framework/TestListener.php";
require_once "../framework/TestResult.php";
require_once "../runner/BaseTestRunner.php";

/**
 * $Id: ResultPrinter.php,v 1.1 2004/08/25 21:43:59 japha Exp $
 *
 * @author <a href="mailto:gantt@cs.montana.edu">Ryan Gantt</a>
 * @version $Revision: 1.1 $
 */
class ResultPrinter extends Object implements TestListener
{
    /**
     * PrintStream
     */
	public $fWriter;
	
	/**
	 * Integer
	 */
	public $fColumn = 0;
	
	public function __construct( PrintStream $writer ) 
	{
		$this->fWriter = $writer;
	}
	
	/* 
	 * API for use by textui.TestRunner
	 *
	 * @synchronized
	 */
	public function _print( TestResult $result, $runTime )
	{
		$this->printHeader( $runTime );
		$this->printErrors( $result );
		$this->printFailures( $result );
		$this->printFooter( $result );
	}

	function printWaitPrompt() 
	{
		$this->getWriter()->println();
		$this->getWriter()->println("<RETURN> to continue");
	}
	
	/* 
	 * Internal methods 
	 */
	protected function printHeader( $runTime ) 
	{
		$this->getWriter()->println();
		$this->getWriter()->println( "Time: " . $this->elapsedTimeAsString( $runTime ) );
	}
	
	/**
	 * THESE METHODS ARE NOT FULLY IMPLEMENTED
	 */	
	protected function printErrors( TestResult $result ) 
	{
		$this->printDefects( $result->errors(), $result->errorCount(), "error" );
	}
	
	protected function printFailures( TestResult $result ) 
	{
		$this->printDefects( $result->failures(), $result->failureCount(), "failure" );
	}
	
	protected function printDefects( Collection $booBoos, $count, $type ) 
	{
		if ( $count == 0 ) 
		{
		    return;
		}
		if ( $count == 1 )
		{
			$this->getWriter()->println("There was " . $count . " " . $type . ":<br/>");
		}
		else
		{
			$this->getWriter()->println("There were " . $count . " " . $type . "s:<br/>");
		}
		$i = 1;
		for ( $e = new EnumerationIterator( $booBoos ), $e->reset(); $e->hasNext(); $e->next() ) 
		{
		    $this->printDefect( $e->current(), $i++ );
		}
	}
	
	/**
	 * Only for public testing purposes
	 */
	public function printDefect( TestFailure $booBoo, $count )
	{ 
		$this->printDefectHeader( $booBoo, $count );
		$this->printDefectTrace( $booBoo );
	}

	/**
	 * I feel like making this a println, then adding a line giving the throwable a chance to print something
	 * before we get to the stack trace.
     */
	protected function printDefectHeader( TestFailure $booBoo, $count ) 
	{
		$this->getWriter()->println( $count . ") " . $booBoo->failedTest()->toString() );
	}

	protected function printDefectTrace( TestFailure $booBoo ) 
	{
		$this->getWriter()->println( BaseTestRunner::getFilteredTrace( $booBoo->trace() ) );
	}

	protected function printFooter( TestResult $result ) 
	{
		if ( $result->wasSuccessful() ) 
		{
			$this->getWriter()->println();
			$this->getWriter()->_print("OK");
			$this->getWriter()->println(" (".$result->runCount()." test".($result->runCount() == 1 ? "": "s").")");

		} 
		else 
		{
			$this->getWriter()->println();
			$this->getWriter()->println("FAILURES!!!");
			$this->getWriter()->println("Tests run: ".$result->runCount(). ",  Failures: ".$result->failureCount(). ",  Errors: ".$result->errorCount());
		}
	    $this->getWriter()->println();
	}

	/**
	 * Returns the formatted string of the elapsed time.
	 * Duplicated from BaseTestRunner. Fix it.
	 */
	protected function elapsedTimeAsString( $runTime ) 
	{
		//return NumberFormat::getInstance()->format( $runTime / 1000 );
		return ( $runTime / 1000 );
	}

	public function getWriter() 
	{
		return $this->fWriter;
	}
	/**
	 * @see junit.framework.TestListener#addError(Test, Throwable)
	 */
	public function addError( Test $test, Throwable $t ) 
	{
		$this->getWriter()->_print("E");
	}

	/**
	 * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
	 */
	public function addFailure( Test $test, AssertionFailedError $t ) 
	{
		$this->getWriter()->_print("F");
	}

	/**
	 * @see junit.framework.TestListener#startTest(Test)
	 */
	public function startTest( Test $test ) 
	{
		$this->getWriter()->_print(".");
		if ( $this->fColumn++ >= 40 ) 
		{
			$this->getWriter()->println();
			$this->fColumn = 0;
		}
	}
	
	/**
	 * @see junit.framework.TestListener#endTest(Test)
	 */
	public function endTest( Test $test ){}
}